﻿#include "windows.h"
#include "tchar.h"

#pragma warning (disable : 4996)
#pragma comment (lib, "user32")
#pragma comment (lib, "gdi32")

class CWnd;

HWND 		g_hWnd		= NULL;
HBITMAP 	g_hBitmap 	= NULL;
WNDPROC 	g_Proc		= NULL;
CWnd		*g_cWnd 	= NULL;														// 窗口链的root
CWnd		*g_cWndLast = NULL;														// 最近绘制边框的窗口，可以避免鼠标移动一下绘制一次
RECT		g_Select;	
BOOL		g_SelectWnd = FALSE;	

LONG		CX, CY;

VOID PrintInfo(LPTSTR Format, ...){
	va_list Args;
	TCHAR   String[8192];

	va_start(Args, Format);
	_vstprintf(String, Format, Args);
	va_end(Args);

	OutputDebugString(String);
}

class CWnd {
public:
	CWnd (CWnd * Parent, LPRECT WindowRect, LPRECT ClientRect);
	~CWnd();

	CWnd * 	HitTest(POINT Pt);
	LPRECT	GetRect(POINT Pt) { return PtInRect(&m_ClientRect, Pt) ? &m_ClientRect : &m_WindowRect;	};

private:
	VOID	AddChild(CWnd * Child);

	RECT 	m_WindowRect;
	RECT 	m_ClientRect;

	CWnd	*m_Parent;				// 父节点
	CWnd	*m_First;				// 第一个子节点
	CWnd	*m_Last;				// 最后一个子节点
	CWnd	*m_Next;				// 上一个节点
	CWnd	*m_Prev;				// 下一个节点
};

CWnd::CWnd(CWnd * Parent, LPRECT WindowRect, LPRECT ClientRect){
	m_Parent 	 = Parent;
	m_First 	 = NULL;
	m_Last  	 = NULL;
	m_Next		 = NULL;
	m_Prev	     = NULL;

	CopyRect(&m_WindowRect, WindowRect);
	CopyRect(&m_ClientRect, ClientRect);

	if (Parent) Parent->AddChild(this);
}

CWnd::~CWnd() {	
	if (m_Parent) {
		if (m_Parent->m_First == this) {
			m_Parent->m_First = m_Next;
		}
		if (m_Parent->m_Last == this) {
			m_Parent->m_Last  = m_Prev;
		}
	}

	if (m_Prev) m_Prev->m_Next = m_Next;
	if (m_Next) m_Next->m_Prev = m_Prev;    


	CWnd * Current = m_First;
	CWnd * Next	= NULL;

	for (; Current; Current = Next) {
		Next = Current->m_Next;
		delete Current;
	}
}

VOID CWnd::AddChild(CWnd * child) {					// 加到窗口的最前，后加入的Z-ORDER更低。 Z-ORDER越大，越在显示上层。
	child->m_Parent = this;							// 对child的影响
	child->m_Prev	= m_Last;						// child加到链尾
	if (m_Last) m_Last->m_Next = child;				// 链前后咬合
	m_Last = child;									// 链上下咬合
	if (!m_First) m_First = child;					// 无子项的情况
}

CWnd * CWnd::HitTest(POINT Pt) {
	if (!m_First) return this;																		// 子窗口没有

	for (CWnd * child = m_First; child; child = child->m_Next) {
		
		if (PtInRect(&child->m_WindowRect, Pt)) {
			return child->HitTest(Pt);
		}
	}

	return this;
}

VOID GetRects(HWND hWnd, LPRECT WindowRect, LPRECT ClientRect) {
	GetWindowRect(hWnd, WindowRect);
	GetClientRect(hWnd, ClientRect);
	ClientToScreen(hWnd, (LPPOINT) ClientRect);
	ClientRect->right  += ClientRect->left;
	ClientRect->bottom += ClientRect->top;
}

VOID CreateCWnd(HWND hWndParent, CWnd * cWndParent) {
	HWND hWndChild = GetTopWindow(hWndParent);
	
	for (; hWndChild; hWndChild = GetNextWindow(hWndChild, GW_HWNDNEXT)) {
		if (!IsWindowVisible(hWndChild)) 		continue;
		if (IsIconic(hWndChild)) 				continue;

		RECT WindowRect;
		RECT ClientRect;
		GetRects(hWndChild, &WindowRect, &ClientRect);
		if (WindowRect.right <= 0 || WindowRect.bottom <= 0) continue;								// 隐藏窗口
		CWnd * cWnd = new CWnd(cWndParent, &WindowRect, &ClientRect);
		CreateCWnd(hWndChild, cWnd);
	}
}

VOID CreateDesktopCWnd() {
	HWND hWndDesktop = GetDesktopWindow();
	RECT WindowRect;
	RECT ClientRect;
	GetRects(hWndDesktop, &WindowRect, &ClientRect);

	g_cWnd = new CWnd(NULL, &WindowRect, &ClientRect);
	CreateCWnd(hWndDesktop, g_cWnd);
	g_cWndLast = NULL;
}

VOID OnPaint(HDC hdc) {																// 恢复存储的桌面显示
	HDC hdc1 = CreateCompatibleDC(hdc);
	SelectObject(hdc1, g_hBitmap);
	BitBlt(hdc, 0, 0, CX, CY, hdc1, 0, 0, SRCCOPY);									// 屏幕显示桌面
	DeleteDC(hdc1);
}

VOID SaveDesktopBitMap() {
	HDC hdcScreen = GetDC(NULL);													// 包含桌面位图
	HDC hdc = CreateCompatibleDC(hdcScreen);										// 此时没有位图
	SelectObject(hdc, g_hBitmap);													// 包含位图
	BitBlt(hdc, 0, 0, CX, CY, hdcScreen, 0, 0, SRCCOPY);							// 将屏幕位图保存起来
	ReleaseDC(NULL, hdcScreen);
	DeleteDC(hdc);	
}

VOID GetMessagePoint(LPPOINT Pt) {
	DWORD  Pos = GetMessagePos();													// 当前鼠标位置
	POINTS Pts = MAKEPOINTS(Pos);
	Pt->x = Pts.x;
	Pt->y = Pts.y;
}

VOID OnPaintEdge() {
	POINT  Pt;
	GetMessagePoint(&Pt);

	CWnd * cWnd = g_cWnd->HitTest(Pt);
	if (cWnd == g_cWndLast) return;													// 避免鼠标重复绘制
	g_cWndLast = cWnd;

	RECT Rect;
	CopyRect(&Rect, cWnd->GetRect(Pt));

	HDC hdc = GetDC(g_hWnd);														// 获得DC
	HDC hdc1 = CreateCompatibleDC(hdc);
	SelectObject(hdc1, g_hBitmap);
	HBITMAP hBitmap = CreateCompatibleBitmap(hdc, CX, CY);
	BitBlt(hdc, 0, 0, CX, CY, hdc1, 0, 0, SRCCOPY);
	DeleteDC(hdc1);

	HPEN hPen = CreatePen(PS_SOLID, 3, 0xFF);										// 红色以突出显示
	SelectObject(hdc, GetStockObject(NULL_BRUSH));									// 不填充
	SelectObject(hdc, hPen);
	InflateRect(&Rect, -1, -1);														// 画笔厚度为3(-1, 0, 1)
	Rectangle(hdc, Rect.left, Rect.top, Rect.right, Rect.bottom);					// 画Client边框
	DeleteObject(hPen);
	ReleaseDC(g_hWnd, hdc);
	DeleteObject(hBitmap);
}

VOID OnPaintSelect() {
	POINT  Pt;
	GetMessagePoint(&Pt);
	g_Select.right  = Pt.x;
	g_Select.bottom = Pt.y;

	RECT Rect;
	CopyRect(&Rect, &g_Select);

	HDC hdc = GetDC(g_hWnd);														// 获得DC
	HDC hdc1 = CreateCompatibleDC(hdc);
	SelectObject(hdc1, g_hBitmap);
	HBITMAP hBitmap = CreateCompatibleBitmap(hdc, CX, CY);
	BitBlt(hdc, 0, 0, CX, CY, hdc1, 0, 0, SRCCOPY);
	DeleteDC(hdc1);

	HPEN hPen = CreatePen(PS_SOLID, 1, 0xFF);										// 红色以突出显示
	SelectObject(hdc, GetStockObject(NULL_BRUSH));									// 不填充
	SelectObject(hdc, hPen);
	Rectangle(hdc, Rect.left, Rect.top, Rect.right, Rect.bottom);					// 画Client边框
	DeleteObject(hPen);
	ReleaseDC(g_hWnd, hdc);
	DeleteObject(hBitmap);
}

VOID OnMouseMove(WPARAM fKeys) {
	fKeys = fKeys & MK_LBUTTON;
	if (!fKeys) {
		OnPaintEdge();
		g_SelectWnd = TRUE;
	}
	else {
		OnPaintSelect();
		g_SelectWnd = FALSE;
	}
}

VOID OnLButtonDown() {
	POINT  Pt;
	GetMessagePoint(&Pt);
	g_Select.left = Pt.x;
	g_Select.top  = Pt.y;
}

VOID CheckSelect() {
	if (g_Select.left > g_Select.right) {
		LONG left = g_Select.left;
		g_Select.left  = g_Select.right;
		g_Select.right = left;
	}

	if (g_Select.top > g_Select.bottom) {
		LONG top = g_Select.top;
		g_Select.top  = g_Select.bottom;
		g_Select.bottom = top;
	}
}

VOID CopyBitmap() {
	if (!OpenClipboard (g_hWnd)) 			return;
	if (g_Select.right  == g_Select.left)  	return;
	if (g_Select.bottom == g_Select.right) 	return;

	CheckSelect();

	EmptyClipboard();
	HDC hdc = GetDC(g_hWnd);
	HDC hdc1 = CreateCompatibleDC(hdc);
	HDC hdc2 = CreateCompatibleDC(hdc);

	HBITMAP hBitmap = CreateCompatibleBitmap(hdc, g_Select.right - g_Select.left, g_Select.bottom - g_Select.top);
	ReleaseDC(g_hWnd, hdc);

	SelectObject(hdc1, hBitmap);
	SelectObject(hdc2, g_hBitmap);
	BitBlt(hdc1, 0, 0, g_Select.right - g_Select.left, g_Select.bottom - g_Select.top, hdc2, g_Select.left, g_Select.top, SRCCOPY);

	SetClipboardData(CF_BITMAP, hBitmap);
	CloseClipboard();

	DeleteObject(hBitmap);
	DeleteDC(hdc1);
	DeleteDC(hdc2);
}

VOID OnLButtonUp() {
	POINT  Pt;
	GetMessagePoint(&Pt);

	if (g_SelectWnd) {															// 捕捉的是窗口
		CopyRect(&g_Select, g_cWndLast->GetRect(Pt));
	}
	else {
		g_Select.right  = Pt.x;
		g_Select.bottom = Pt.y;
	}

	CopyBitmap();

	DestroyWindow(g_hWnd);														// 销毁窗口
	delete g_cWnd;
	g_hWnd 		= NULL;
	g_cWnd 		= NULL;
	g_cWndLast 	= NULL;
}

LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM w, LPARAM l) {
	switch(msg){
	case WM_ERASEBKGND:																// 不删除窗口
		return 1;
	case WM_PAINT:																	// 恢复存储的桌面显示
		PAINTSTRUCT Paint;
		OnPaint(BeginPaint(hWnd, &Paint));											// 绘图
		EndPaint(hWnd, &Paint);
		return 0;
	case WM_LBUTTONDOWN:
		OnLButtonDown();
		return 0;
	case WM_LBUTTONUP:
		OnLButtonUp();
		return 0;
	case WM_MOUSEMOVE:
		OnMouseMove(w);
		return 0;
	case WM_NCHITTEST:
		return HTCLIENT;
	}

	return CallWindowProc(g_Proc, hWnd, msg, w, l);
} 

BOOL CreateFreezeWindow() {
	g_hWnd = CreateWindowEx(WS_EX_TOOLWINDOW, 										// 隐藏任务栏图标
		_T("STATIC"), _T(""), WS_POPUP, 											// 不用注册窗口类
		0, 0, CX, CY, 																// 全屏
		GetDesktopWindow(), NULL, GetModuleHandle(NULL), NULL);						// 以Root为父窗口
	if (!g_hWnd) return FALSE;

	g_Proc = (WNDPROC) SetWindowLong(g_hWnd, GWL_WNDPROC, (LONG) WindowProc);		// 实现捕捉
	SetFocus(g_hWnd);
	ShowWindow(g_hWnd, SW_SHOW);													// 显示窗口

	return TRUE;
}

VOID CALLBACK KeyTimerProc(HWND, UINT, UINT id, DWORD) {							// 从WM_TIMER消息而来 50ms一次
	if (0x8000 & GetKeyState('Q') && 0x8000 & GetKeyState(VK_CONTROL)){				// 按CONTROL + Q键，认为是QUIT。其它无窗口函数可以参考此方式。
		PostQuitMessage(0);															// 把WM_QUIT放入消息队列，令GetMessage返回FALSE,以退出消息循环
		return;
	}

	if (0x8000 & GetKeyState('1') && 0x8000 & GetKeyState(VK_CONTROL)){				// 按CONTROL + 1键，认为是激活，创建窗口。
		if (g_hWnd) return;															// 避免重复创建
		SaveDesktopBitMap();														// 更新桌面位图
		CreateDesktopCWnd();														// 更新桌面窗口
		CreateFreezeWindow();														// 创建窗口
		return;
	}

	if (g_hWnd) SetWindowPos(g_hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);			// 保证窗口在最上层
}

int CALLBACK _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow){
	CX = GetSystemMetrics(SM_CXSCREEN);												// 均是屏幕尺寸
	CY = GetSystemMetrics(SM_CYSCREEN);

	HDC hdcScreen = GetDC(NULL);													// 包含桌面位图
	g_hBitmap = CreateCompatibleBitmap(hdcScreen, CX, CY);							// 创建位图
	ReleaseDC(NULL, hdcScreen);
	
	UINT id = SetTimer(NULL, NULL, 50,  KeyTimerProc);								// 程序退出/窗口激活/窗口销毁/窗口拉至最上层

	MSG msg;
	while (GetMessage(&msg, NULL, NULL, NULL)){
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	DeleteObject(g_hBitmap);														// 销毁位图
	if (g_cWnd) delete g_cWnd;
	if (g_hWnd) DestroyWindow(g_hWnd);
	KillTimer(NULL, id);															// 关闭定时器

	return msg.wParam;
}
